package com.ymt.bpm.engine.handler.activity.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.ymt.bpm.dao.MDao;
import com.ymt.bpm.dao.Mapper;
import com.ymt.bpm.engine.handler.activity.AssigneeService;
import com.ymt.bpm.model.PPi;
import com.ymt.bpm.model.PUserRef;
import com.ymt.bpm.service.engine.taskcenter.DelegateService;
import com.ymt.bpm.util.Const;
import org.activiti.engine.delegate.DelegateTask;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Johnny on 2017/4/22.
 */
@Service
public class AssigneeServiceImpl implements AssigneeService {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private Environment env;

    @Autowired
    private MDao dao;

    @Autowired
    private DelegateService dlgs;

    @Override
    public List<JSONObject> getAssigneeByTaskConfig(String tenantId,
                                                    JSONObject activityConf,
                                                    DelegateTask dt, PPi pi, PUserRef piUserRef) {
        List<JSONObject> users = null;

        String assigneeType = activityConf.getString("assigneeType");
        if (log.isDebugEnabled()) {
            log.debug("assigneeType="+assigneeType);
        }

        switch (assigneeType) {
            case "user":
                users = byUser(tenantId, activityConf);
                break;
            case "role":
                users = byRole(tenantId, activityConf);
                break;
            case "position":
                users = byPosition(tenantId, activityConf);
                break;
            case "pgposition":
                users = byPgPosition(tenantId, activityConf);
                break;
            case "relation":
                users = byRelation(tenantId, activityConf, dt, pi, piUserRef);
                break;
            case "ruletable":
                //TODO
                break;
            default:
                users = new ArrayList<JSONObject>();
                //do nothing
        }
        users = dlgs.filterAssignee(tenantId, pi.getBpdId(), pi.getVersionid(), users);
        return users;
    }

    private List<JSONObject> byUser(String tenantId, String userIds){
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("userIds", userIds);
        List<Map<String, Object>> list = dao.selectList(Mapper.AssigneeMapper, "selectAssigneeByUserIds", paramMap);
        List<JSONObject> users = toUserList(list);
        return users;
    }

    /**
     * @MethodName: byUser
     * @Description: 方法说明:指定办理人
     * @param activityConf
     * @return List<User>assigneeUser
     */
    private List<JSONObject> byUser(String tenantId, JSONObject activityConf){
        String userIds = JSONPath.eval(activityConf, "$.assigneeUser.ids").toString();
        return byUser(tenantId, userIds);
    }

    /**
     * @MethodName: byRole
     * @Description: 方法说明：通过指定角色
     * @param activityConf
     * @return List<JSONObject>
     */
    private List<JSONObject> byRole(String tenantId, JSONObject activityConf){
        String roleId = JSONPath.eval(activityConf, "$.assigneeRole.roleId").toString();
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("roleId", roleId);
        List<Map<String, Object>> list = dao.selectList(Mapper.AssigneeMapper, "selectUsersByRole", paramMap);
        List<JSONObject> users = toUserList(list);
        return users;
    }

    /**
     * @MethodName: byPosition
     * @Description: 方法说明：通过指定部门岗位查人员
     * @param activityConf
     * @return List<JSONObject>
     */
    private List<JSONObject> byPosition(String tenantId, JSONObject activityConf){
        String orgId = JSONPath.eval(activityConf, "$.assigneePosition.orgId").toString();
        String posId = JSONPath.eval(activityConf, "$.assigneePosition.posId").toString();
        return byPosition(tenantId, orgId, posId);
    }
    private List<JSONObject> byPosition(String tenantId, String orgId, String posId) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("orgId", orgId);
        paramMap.put("posId", posId);
        List<Map<String, Object>> list = dao.selectList(Mapper.AssigneeMapper, "selectUsersByOrgPos", paramMap);
        List<JSONObject> users = toUserList(list);
        return users;
    }

    /**
     * @MethodName: byPosition
     * @Description: 方法说明：通过指定项目组岗位查人员
     * @param activityConf
     * @return List<JSONObject>
     */
    private List<JSONObject> byPgPosition(String tenantId, JSONObject activityConf){
        String groupId = JSONPath.eval(activityConf, "$.assigneePgPosition.groupId").toString();
        String posId = JSONPath.eval(activityConf, "$.assigneePgPosition.posId").toString();
        return byPgPosition(tenantId, groupId, posId);
    }
    private List<JSONObject> byPgPosition(String tenantId, String groupId, String posId) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("groupId", groupId);
        paramMap.put("posId", posId);
        List<Map<String, Object>> list = dao.selectList(Mapper.AssigneeMapper, "selectUsersByGroupPos", paramMap);
        List<JSONObject> users = toUserList(list);
        return users;
    }

    private List<JSONObject> byUserLeader(String tenantId, String userIds){
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(Const.TENANT_ID, tenantId);
        paramMap.put("userIds", userIds);
        paramMap.put("relationType", "01");
        List<Map<String, Object>> list = dao.selectList(Mapper.AssigneeMapper, "selectAssigneeByUserExtRef", paramMap);
        List<JSONObject> users = toUserList(list);
        return users;
    }

    /**
     * @MethodName: byRelation
     * @Description: 方法说明:根据流程定义配置的相对关系查询人员
     * @param activityConf
     * @return List<JSONObject>
     */
    private List<JSONObject> byRelation(String tenantId, JSONObject activityConf,DelegateTask dt, PPi pi, PUserRef piUserRef){

        List<JSONObject> users = new ArrayList<JSONObject>();
        List<JSONObject> subjects = null;
        String assigneeRelationSubject = activityConf.getString("assigneeRelationSubject");
        boolean jsonDataEnabled = Boolean.parseBoolean(env.getProperty("bpmp.fmd-json-bizdata", "false"));

		switch(assigneeRelationSubject){//相对于
			case "creator"://流程发起人
                subjects = new ArrayList<JSONObject>();
                JSONObject subject = new JSONObject();
                subject.put("userId", pi.getUserId());
                subject.put("userName", pi.getUserName());
                subject.put("orgId", piUserRef.getDeptId());
                subject.put("orgName", piUserRef.getDeptName());
                subjects.add(subject);
                users = findUsersByRelationSubject(tenantId, activityConf, subjects);
				break;
			case "previousTaskowner"://前序环节处理人
                String activityId = JSONPath.eval(activityConf, "$.assigneeRelationSubjectActivity.activityId").toString();
                Map<String, Object> paramMap1 = new HashMap<String, Object>();
                paramMap1.put(Const.TENANT_ID, tenantId);
                paramMap1.put("activityId", activityId);
                paramMap1.put("piId", pi.getPiId());
                List<Map<String, Object>> list1 = dao.selectList(Mapper.AssigneeMapper, "selectPreviousTaskowner", paramMap1);
                subjects = toUserList(list1);
                users = findUsersByRelationSubject(tenantId, activityConf, subjects);
				break;
			case "formvar"://来自表单变量
                String modelName = JSONPath.eval(activityConf, "$.assigneeRelationSubjectFormvar.parentvarname").toString();
                String userCol = JSONPath.eval(activityConf, "$.assigneeRelationSubjectFormvar.varname").toString();
                Map<String, Object> paramMap2 = new HashMap<String, Object>();
                paramMap2.put(Const.TENANT_ID, tenantId);
                paramMap2.put("piEid", pi.getPiEid());
                paramMap2.put("userCol", userCol);
                List<Map<String, Object>> list2;
                if (jsonDataEnabled) {
                    paramMap2.put("modelName", modelName);
                    list2 = dao.selectList(Mapper.AssigneeMapper, "selectUserFromBodata", paramMap2);
                } else {
                    modelName += (tenantId!=null ? "_"+tenantId : "");
                    paramMap2.put("modelName", modelName);
                    list2 = dao.selectList(Mapper.AssigneeMapper, "selectUserFromBodataNoJson", paramMap2);
                }
                subjects = toUserList(list2);
                users = findUsersByRelationSubject(tenantId, activityConf, subjects);
				break;
			case "processvar"://来自流程变量
                String varname = JSONPath.eval(activityConf, "$.assigneeRelationSubjectProcessvar.varname").toString();
                String userId = JSONPath.eval(dt.getVariable("processVar"), "$.variables."+varname+".value").toString();
                if(null != userId && userId.length()>0){
                    subjects = byUser(tenantId, userId);
                    users = findUsersByRelationSubject(tenantId, activityConf, subjects);
                }
				break;
			default:
			    log.error("the relation provided not found!!");break;
		
		}
        return users;
    }

    private List<JSONObject> findUsersByRelationSubject(String tenantId, JSONObject activityConf, List<JSONObject> subjects){
        List<JSONObject> users = new ArrayList<JSONObject>();
        String assigneeRelationRelation = activityConf.getString("assigneeRelationRelation");
		switch(assigneeRelationRelation){
			case "same"://与指定人相同
				users = subjects;
				break;
			case "leader"://直属领导
				if (subjects!=null && subjects.size()>0) {
			        List<String> userIds = new ArrayList<String>();
			        for (JSONObject subject : subjects) {
			            userIds.add(subject.getString("userId"));
                    }
                    users = byUserLeader(tenantId, StringUtils.join(userIds,","));
                }
				break;
			case "deptManager"://部门经理
				//users.add(userDao.selectUserByPosition("10",userId));
				break;
			case "deptViceManager"://部门副经理
				//users.add(userDao.selectUserByPosition("11",userId));
				break;
			case "VP"://分管副总
				//users.add(userDao.selectUserByPosition("00",userId));
				break;
			case "position"://所在部门岗位(部门为主部门)
                if (subjects!=null && subjects.size()>0) {
			        String posId = activityConf.getJSONObject("assigneeRelationRelationPosition").getString("posId");
			        log.debug("getByRelation relation posId="+posId);
                    for (JSONObject subject : subjects) {
                        List<JSONObject> usersFromPos = byPosition(tenantId, subject.getString("orgId"), posId);
                        users.addAll(usersFromPos);
                    }
                }
				break;
            case "pgposition"://所在部门岗位(部门为主部门)
                if (subjects!=null && subjects.size()>0) {
                    String posId = activityConf.getJSONObject("assigneeRelationRelationPgPosition").getString("posId");
                    log.debug("getByRelation relation posId="+posId);
                    for (JSONObject subject : subjects) {
                        Map<String, Object> pMap1 = new HashMap<String, Object>();
                        pMap1.put(Const.TENANT_ID, tenantId);
                        pMap1.put("userId", subject.getString("userId"));
                        List<String> groups = dao.selectList(Mapper.AssigneeMapper, "queryUserGroup", pMap1);
                        if (groups!=null && groups.size()>0) {
                            for (String groupId : groups) {
                                List<JSONObject> usersFromPos = byPgPosition(tenantId, groupId, posId);
                                users.addAll(usersFromPos);
                            }
                        }
                    }
                }
                break;
			default :
				log.error("the relative relation provided not found!!");
				break;
		}
        return users;
    }

    private List<JSONObject> toUserList(List<Map<String, Object>> list) {
        List<JSONObject> users = new ArrayList<JSONObject>();
        if (list!=null && list.size()>0) {
            for (Map<String, Object> map : list) {
                JSONObject user = new JSONObject();
                user.put("userId", map.get("USER_ID"));
                user.put("userName", map.get("DISPLAY_NAME"));
                user.put("orgId", map.get("ORG_ID"));
                user.put("orgName", map.get("ORG_NAME"));
                if (map.containsKey("DEPT_ID")) {   //use PUserRef dept info to replace main org info
                    user.put("orgId", map.get("DEPT_ID"));
                    user.put("orgName", map.get("DEPT_NAME"));
                }
                if (map.containsKey("ROLE_ID")) {
                    user.put("roleId", map.get("ROLE_ID"));
                    user.put("roleName", map.get("ROLE_NAME"));
                }
                users.add(user);
            }
        }
        return users;
    }

}
